home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 426-450 / disk_437 / flip / flip2.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  376 lines

  1. /***************************************************************
  2. *  FLIP v2.0  02/25/90
  3. *  © Copyright 1990 by Timm Martin and Mike Monaco
  4. *  Based heavily on the Shuffle program written by Ray Lambert
  5. *  *** This program is FreeWare ***
  6. *
  7. *  This program is the same as FLIP v1.0 except that it uses
  8. *  an assembler input handler, eliminating the need to compile
  9. *  it in large code/large data format.  This also means that
  10. *  it's about 1K smaller than FLIP v1.0!
  11. *
  12. *  You will get a ptr/ptr warning when you compile.  You will
  13. *  also get a linker warning about replacing __main.  These
  14. *  are OK and do not affect the program.
  15. ****************************************************************/
  16.  
  17. #include <stdio.h>
  18. #include <intuition/intuition.h>
  19. #include <intuition/intuitionbase.h>
  20. #include <intuition/screens.h>
  21. #include <exec/io.h>
  22. #include <exec/interrupts.h>
  23. #include <exec/ports.h>
  24. #include <exec/tasks.h>
  25. #include <graphics/layers.h>
  26. #include <graphics/clip.h>
  27. #include <graphics/text.h>
  28. #include <devices/input.h>
  29. #include <devices/inputevent.h>
  30. #include <devices/timer.h>
  31. #include <libraries/dos.h>
  32.  
  33. #asm
  34. InputEvent    EQU     0
  35. SOFFSET       SET     0
  36. ie_NextEvent  EQU     SOFFSET
  37. SOFFSET       SET     SOFFSET+4
  38. ie_Class      EQU     SOFFSET
  39. SOFFSET       SET     SOFFSET+1
  40. ie_SubClass   EQU     SOFFSET
  41. SOFFSET       SET     SOFFSET+1
  42. ie_Code       EQU     SOFFSET
  43. SOFFSET       SET     SOFFSET+2
  44. ie_Qualifier  EQU     SOFFSET
  45. SOFFSET       SET     SOFFSET+2
  46.  
  47.               xdef    _LVOSignal
  48. #endasm
  49.  
  50. /* name of the message port for input handler to reach this process */
  51. char *port_name = "FlipPort";
  52.  
  53. /* signals and signal bits */
  54.  
  55. ULONG
  56.   window_signal,
  57.   screen_signal,
  58.   window_signal_bit = -1L,
  59.   screen_signal_bit = -1L,
  60.   all_signal_bits,
  61.   exit_bits;
  62.  
  63. /* needs to be declared globally for inline assembly */
  64. struct InputEvent *ie;
  65.  
  66. /* flags */
  67. UBYTE
  68.   input_opened   = 0,
  69.   handler_active = 0;
  70.  
  71. /* global variables */
  72. struct Interrupt *handler           = NULL;
  73. struct Task *my_task;
  74. struct IOStdReq *io_req             = NULL;
  75. struct MsgPort *message_port        = NULL;
  76. struct IntuitionBase *IntuitionBase = NULL;
  77. #define IO_REQ_SIZE (long)sizeof(struct IOStdReq)
  78.  
  79. /***************
  80. *  END PROGRAM
  81. ****************/
  82.  
  83. void end_program()
  84. {
  85.   if (handler_active)
  86.   {
  87.     io_req->io_Command = IND_REMHANDLER;
  88.     io_req->io_Data    = (APTR)handler;
  89.     DoIO( io_req );
  90.   }
  91.  
  92.   if (input_opened) CloseDevice( io_req );
  93.   if (io_req)       FreeMem( io_req, IO_REQ_SIZE );
  94.   if (handler)      FreeMem( handler, (LONG)sizeof(struct Interrupt) );
  95.   
  96.   if (message_port) DeletePort( message_port );
  97.  
  98.   if (screen_signal_bit != -1L) FreeSignal( screen_signal_bit );
  99.   if (window_signal_bit != -1L) FreeSignal( window_signal_bit );
  100.  
  101.   if (IntuitionBase) CloseLibrary( IntuitionBase );
  102.  
  103.   exit( 0 );
  104. }
  105.  
  106. /***************
  107. *  KEY HANDLER
  108. ****************/
  109.  
  110. /*
  111. This function is the input handler code used to monitor for left-Amiga-M and
  112. left-Amiga-N key presses.  It's not doing too much, so there shouldn't be any
  113. noticable degradation in the input process.  A pointer to the active input
  114. even chain is passed to this function in register A0, hence the need for
  115. inline assembler.  Thanks to Mike Monaco (Dr. Assembler) for this tidbit!
  116.  
  117. Assembler Notes:
  118.  
  119. To allow for use with the small data and small code models, particularly
  120. small data model, variables used in the handler had to be addressable such
  121. that the assembler would not use the offset register associated with the
  122. small data models.  (For the MANX compiler/assembler that is A4) The reason
  123. is that the handler is invoked as an interrupt and does not have the luxury
  124. of having the registers in the same state as the task which installed it.
  125. (ie. A4 would be garbage in relation to the handler code) 
  126.  
  127. Also data created during startup and instalation must be available for
  128. signaling the task into action. This data must be stored so it is addressable
  129. in the small data model.  The only way I could think of doing this was to
  130. allocate storage space within the code and use (pc) addressing for the
  131. constants. Orignally I also used the same method for saving the variable data
  132. but wasn't sure if the handler could be invoked while it is was processing
  133. other data, so is switched to using the stack for that. I didn't have any
  134. problems the other way though.
  135.  
  136. Ok. I could have used the farcode and fardata directives, but that wouldn't
  137. have been any fun.
  138.  
  139. --Mike Monaco
  140. */
  141.  
  142. struct InputEvent *key_handler()
  143. {
  144.   ;
  145.   #asm
  146.   move.l  a0,-(sp)    ; save beginning of event chain
  147.  
  148.   Key_For_Loop:
  149.     move.l    a0,d0                   ; see if its NULL
  150.     beq.s     Key_For_Exit            ; yes - with event chain 
  151.     move.b    ie_Class(a0),d0         ; RAWKEY = $0001
  152.     subq.b    #1,d0                   ; is it a RAWKEY event
  153.     bne.s     Key_Next                ; no - get next event
  154.     move.w    ie_Qualifier(a0),d0     ; IEQUALIFIER_LCOMMAND = $0040
  155.     and.w     #$0040,d0               ; was Left Amiga pressed
  156.     beq.s     Key_Next                ; no - get next event 
  157.     move.w    ie_Code(a0),d0          ; looking for $36 for screen
  158.                                       ; and $37 for window
  159.   Key_Check_Screen:
  160.     sub.b     #$36,d0                 ; is it screen
  161.     bne.s     Key_Check_Window        ; no - might be window
  162.  
  163.     move.l    _ss_(pc),d0             ; yes - user wants to flip screens
  164.     bra.s     Key_Send_Signal
  165.  
  166.   Key_Check_Window:
  167.     sub.b     #$01,d0                 ; is it window
  168.     bne.s     Key_Next                ; nope - we dont want this baby
  169.  
  170.     move.l    _ws_(pc),d0             ; yes - user wants to flip windows
  171.  
  172.   Key_Send_Signal:                    ; signal task to perform flip
  173.     move.l    a0,-(sp)                ; save a0
  174.     move.l    _mt_(pc),a1
  175.     move.l    $4,a6                   ;Signal( my_task, window_signal );
  176.     jsr       _LVOSignal(a6)          ;           a1         d0
  177.  
  178.   Key_Clear_Event:                    ; ready to remove event
  179.     move.l    (sp)+,a0                ; restore a0
  180.     move.b    #0,ie_Class(a0)         ; remove event by clearing Class
  181.   Key_Next:
  182.     move.l    ie_NextEvent(a0),a0     ; get next pointer in a0
  183.     bra.s     Key_For_Loop
  184.  
  185.   Key_For_Exit:
  186.     move.l    (sp)+,d0                ; return beginning of event chain
  187.                                       ; for other handlers to process
  188.   #endasm
  189.   ;
  190.  
  191.   return ();
  192. }
  193.  
  194. #asm
  195.   cseg              ; storage must be accessable but not
  196.   ds.l   0          ; restricted by the small data model
  197.   _ws_   dc.l  0    ; window signal created during startup
  198.   _ss_   dc.l  0    ; screen signal created during startup
  199.   _mt_   dc.l  0    ; task pointer found during starup
  200. #endasm
  201.  
  202. /*******************
  203. *  INSTALL HANDLER
  204. ********************/
  205.  
  206. void install_handler()
  207. {
  208.   /* try to allocate signal bits */
  209.   if ((screen_signal_bit = AllocSignal( -1L )) == -1L ||
  210.       (window_signal_bit = AllocSignal( -1L )) == -1L)
  211.     end_program();
  212.  
  213.   /* calculate the bit masks */
  214.   screen_signal = 1L << screen_signal_bit;
  215.   window_signal = 1L << window_signal_bit;
  216.  
  217.   /* get a pointer to this process for signalling purposes */
  218.   my_task = FindTask( NULL );
  219.  
  220.   /* get a message port */
  221.   if (!(message_port = CreatePort( port_name, 0L )))
  222.     end_program();
  223.  
  224.   /* Init Std IO structure */
  225.   if (!(io_req = (struct IOStdReq *) 
  226.                  AllocMem( IO_REQ_SIZE, MEMF_PUBLIC|MEMF_CLEAR )))
  227.     end_program();
  228.   io_req->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  229.   io_req->io_Message.mn_Node.ln_Pri  = 0;
  230.   io_req->io_Message.mn_ReplyPort    = message_port;
  231.  
  232.   /* open the input.device */ 
  233.   if (!(input_opened = (OpenDevice( "input.device", 0L, io_req, 0L ) == 0)))
  234.     end_program();
  235.  
  236.   /* store required values in code segment of handler */
  237.   ;
  238.   #asm
  239.     lea       _ws_,a0
  240.     move.l    _window_signal,(a0)
  241.     lea       _ss_,a0
  242.     move.l    _screen_signal,(a0)
  243.     lea       _mt_,a0
  244.     move.l    _my_task,(a0)
  245.   #endasm
  246.   ;
  247.  
  248.   if (!(handler = (struct Interrupt *) 
  249.                   AllocMem( (LONG)sizeof(struct Interrupt), 
  250.                              MEMF_PUBLIC|MEMF_CLEAR )))
  251.     end_program();
  252.  
  253.   /* add the handler */
  254.   handler->is_Code        = (void *)key_handler;
  255.   handler->is_Data        = NULL;
  256.   handler->is_Node.ln_Pri = 51;
  257.   io_req->io_Command      = IND_ADDHANDLER;
  258.   io_req->io_Data         = (APTR)handler;
  259.  
  260.   if (!(handler_active = (DoIO( io_req ) == 0) ))
  261.     end_program();
  262. }
  263.  
  264.  
  265. /******************
  266. *  SHUFFLE SCREEN
  267. *******************/
  268.  
  269. /*
  270. This procedure locks Intuition so nothing funny can happen in between the
  271. test and the execution portions of the "if" statement (this is a multitasking
  272. machine, you know).  Then the procedure checks to see if there is another
  273. screen in line.  If so, the current screen is sent to the back, and the first
  274. window (if any) on the new front screen is activated.
  275. */
  276.  
  277. void shuffle_screen()
  278. {
  279.   register ULONG ilock;
  280.   register struct Screen *screen;
  281.   register struct Window *window;
  282.  
  283.   ilock = LockIBase( NULL );
  284.   screen = IntuitionBase->FirstScreen;
  285.  
  286.   if (screen->NextScreen)
  287.   {
  288.     while (screen->NextScreen) screen = screen->NextScreen;
  289.     ScreenToFront( screen );
  290.     if (window = screen->LayerInfo.top_layer->Window)
  291.       ActivateWindow( window );
  292.   }
  293.  
  294.   UnlockIBase( ilock );
  295.   SetSignal( 0L, screen_signal );
  296. }
  297.  
  298.  
  299. /******************
  300. *  SHUFFLE WINDOW
  301. *******************/
  302.  
  303. /*
  304. This procedure again locks Intuition for reasons mentioned above.  Then it
  305. sends the current window to the background, and activates the new front
  306. window.
  307. */
  308.  
  309. void shuffle_window()
  310. {
  311.   register ULONG ilock;
  312.   register struct Layer *layer, *get_layer;
  313.   register struct Window *window;
  314.  
  315.   ilock = LockIBase( NULL );
  316.   layer = IntuitionBase->FirstScreen->LayerInfo.top_layer;  
  317.   get_layer = NULL;
  318.  
  319.   while (layer->back)
  320.   {
  321.     if (layer->Window && !(layer->Flags & LAYERBACKDROP))
  322.       get_layer = layer;
  323.     layer = layer->back;
  324.   }
  325.  
  326.   if (get_layer)
  327.   {
  328.     WindowToFront( window = get_layer->Window );
  329.     ActivateWindow( window );
  330.   }
  331.  
  332.   UnlockIBase( ilock );
  333.   SetSignal( 0L, window_signal );
  334. }
  335.  
  336.  
  337. /*********
  338. *  _MAIN
  339. **********/
  340.  
  341. /*
  342. This replaces the _main defined in the standard c.lib library.
  343. */
  344.  
  345. void _main()
  346. {
  347.   register ULONG signal;
  348.  
  349.   /* if couldn't open Intuition (we're in trouble!) or if this is already
  350.    * running, end the program
  351.    */
  352.   if (!(IntuitionBase = (struct IntuitionBase *)
  353.                         OpenLibrary( "intuition.library", LIBRARY_VERSION ))
  354.         || FindPort( port_name ))
  355.     end_program();
  356.  
  357.   install_handler();
  358.  
  359.   exit_bits = SIGBREAKF_CTRL_C |
  360.               SIGBREAKF_CTRL_D |
  361.               SIGBREAKF_CTRL_E |
  362.               SIGBREAKF_CTRL_F;
  363.  
  364.   all_signal_bits = screen_signal | window_signal | exit_bits;
  365.  
  366.   SetSignal( 0L, all_signal_bits );
  367.  
  368.   for (;;)
  369.   {
  370.     signal = Wait( all_signal_bits );
  371.     if (signal & exit_bits)     end_program();
  372.     if (signal & screen_signal) shuffle_screen();
  373.     if (signal & window_signal) shuffle_window();
  374.   }
  375. }
  376.